package main

import (
	"bufio"
	"flag"
	"fmt"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"go_19/utils"
	"gopkg.in/go-playground/pool.v3"
	"log"
	"os"
)

var (
	DB *gorm.DB
)

type SqlExecuteInput struct {
	DbConf      string
	SqlFilePath string
	PoolNum     uint
}

func main() {
	input := getSqlExecuteInput()
	fmt.Println(input)
	sqlFile, err := os.Open(input.SqlFilePath)
	if err != nil {
		fmt.Println("Error opening file:", err)
		return
	}

	pool := pool.NewLimited(input.PoolNum)
	batch := pool.Batch()

	scanner := bufio.NewScanner(sqlFile)
	for scanner.Scan() { // 逐行扫描
		if scanner.Text() != "" {
			batch.Queue(optSqlWork(scanner.Text()))
		}
	}
	batch.QueueComplete()
	r := batch.Results()
LOOP:
	for {
		select {
		case processStr, ok := <-r:
			// 读取结果集
			if ok {
				if err := processStr.Error(); err != nil {
					fmt.Println("err", err.Error())
				}
				//fmt.Println(processStr.Value())
			} else {
				break LOOP
			}
		}
	}
	log.Printf("SQL执行器执行完毕。 \n")

	defer func() {
		DB.DB().Close()
		sqlFile.Close()
		pool.Close()
	}()
}

func optSqlWork(sql string) pool.WorkFunc {
	return func(wu pool.WorkUnit) (interface{}, error) {
		if wu.IsCancelled() {
			fmt.Println("协程程当掉了。。。")
			return nil, nil
		}
		optSql(sql)
		return sql, nil
	}
}
func optSql(sql string) {
	if sql != "" {
		DB.Exec(sql)
	}
}

func conDb(mysqlOpenInfo string) (*gorm.DB, error) {
	if db, err := gorm.Open("mysql", mysqlOpenInfo); err != nil {
		return nil, err
	} else {
		db.DB().SetMaxIdleConns(50)
		db.DB().SetMaxOpenConns(50)
		db.LogMode(true)
		return db, nil
	}
}

func getSqlExecuteInput2() {
	var sqlExecuteInput SqlExecuteInput
	log.Printf("欢迎使用！")
	log.Printf("SQL执行器 \n")
	log.Printf("MYSQL连接配置示例：user:pwd@(host:port)/db_name?charset=utf8&parseTime=True&loc=Local")
	log.Printf("连接MYSQL配置:\n")
	input := bufio.NewScanner(os.Stdin)
loop:
	input.Scan()
	mysqlOpenInfo := input.Text()
	if mysqlOpenInfo == "" {
		log.Println("请输入连接MYSQL配置")
		goto loop
	}
	if db, err := conDb(mysqlOpenInfo); err != nil {
		log.Println("MySQL启动异常", err)
		goto loop
	} else {
		DB = db
	}
	sqlExecuteInput.DbConf = mysqlOpenInfo
	log.Printf("请输入执行SQL文件地址:\n")
loop2:
	input.Scan()
	sqlFile := input.Text()
	if sqlFile == "" {
		log.Println("请输入执行SQL文件地址:\n")
		goto loop2
	}
	if !utils.FileExist(sqlFile) {
		log.Println("请输入执行SQL文件地址:\n")
		goto loop2
	}
	sqlExecuteInput.SqlFilePath = sqlFile
	sqlExecuteInput.PoolNum = 1
	log.Printf("请输入协程数量(默认1):\n")
loop3:
	input.Scan()
	poolNum := input.Text()
	if !utils.IsNumeric(poolNum) {
		log.Println("请输入协程数量(默认1)(数字类型):\n:\n")
	}
	goto loop3

}

func getSqlExecuteInput() SqlExecuteInput {
	log.Printf("欢迎使用！\n")
	log.Printf("SQL执行器 \n")

	var sqlExecuteInput SqlExecuteInput
	mysqlOpenInfo := flag.String("mysql_conf", "", "db连接配置 user:pwd@(host:port)/db_name?charset=utf8&parseTime=True&loc=Local")
	sqlFile := flag.String("exec_sql_file_path", "", "执行SQL文件地址")
	poolNum := flag.Uint("pool_num", 1, "协程数量")
	flag.Parse()
	fmt.Println(*mysqlOpenInfo)
	if *mysqlOpenInfo == "" {
		panic("please input mysql_conf!")
	}
	if db, err := conDb(*mysqlOpenInfo); err != nil {
		panic(err)
	} else {
		DB = db
	}

	if *sqlFile == "" {
		panic("please input exec_sql_file_path!")
	}
	if !utils.FileExist(*sqlFile) {
		panic("exec_sql_file_path is err")
	}
	sqlExecuteInput.DbConf = *mysqlOpenInfo
	sqlExecuteInput.SqlFilePath = *sqlFile
	sqlExecuteInput.PoolNum = *poolNum
	return sqlExecuteInput

}
